home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 July / Macworld (1999-07).dmg / Shareware World / Info / For Developers / Mops 3.4.sea / Mops source / PPC source / pnuc2 < prev    next >
Text File  |  1998-12-16  |  16KB  |  853 lines

  1. marker m__pnuc2
  2.  
  3. \                    ======================
  4. \                               I/O
  5. \                    ======================
  6.  
  7.  
  8. 0    value    BUSY        \ FCB of file involved in asynchronous I/O, or zero if none.
  9.                         \ Set from high level, not from here.  Cleared here though,
  10.                         \  by the completion routine.
  11.  
  12. 0    value    CPADDR        \ Completion routine address, or zero if none.  Also serves
  13.                         \  as a flag that the next op is to be asynchronous.
  14.  
  15.  
  16. \ *** Actually, I'm not going to attempt asynch I/O on the PPC yet, since I
  17. \  don't want to have to worry about UPP callbacks!
  18.  
  19.  
  20. \                    ===========================
  21. \                        OTHER SYSTEM CALLS
  22. \                    ===========================
  23.  
  24. \ we can omit all the handle and pointer stuff here in the nucleus, and just
  25. \  use SYSCALLs in pStruct.
  26.  
  27. sysCall  FreeMem
  28. sysCall  MaxMem
  29. sysCall  EventAvail
  30. sysCall  WaitNextEvent
  31. sysCall  FindWindow
  32. sysCall  BlockMoveData
  33.  
  34. : FREE        FreeMem  ;
  35.  
  36.     variable    growBytes
  37.  
  38. : FREEBLK    growBytes  MaxMem  ;
  39.  
  40. : EVENT?        \ ( mask -- b )
  41.     fEvent  EventAvail 0<>  ;
  42.  
  43. : ?EVENT    event?  ;            \ legacy name
  44.  
  45. : NEXTEVENT        \ ( ^event mask -- b )
  46.     swap
  47.     TEidle_vect
  48.     sleepTicks
  49.     MMRgn
  50.     WaitNextEvent
  51. ;
  52.  
  53. variable  WPtr
  54.     
  55. : FIND-WINDOW    \ ( point -- part# ^window )
  56.     WPtr
  57.     FindWindow
  58.     WPtr @  ;
  59.  
  60.  
  61.  
  62. \                =========================
  63. \                LOW-LEVEL STRING HANDLING
  64. \                =========================
  65.  
  66.  
  67. : FILL  { addr len char -- }
  68.     len  0EXIT
  69.     len FOR
  70.         char  addr c!
  71.         1 ++> addr
  72.     NEXT
  73. ;
  74.  
  75. : ERASE        \ ( addr len -- )
  76.     0 fill  ;
  77.  
  78. : BLANKS    \ ( addr len -- )
  79.     $ 20  fill  ;
  80.  
  81.  
  82. : (S=)  { addr1 addr2 len -- b }
  83.     len
  84.     FOR    addr1 c@  addr2 c@  <>
  85.         IF  UNFOR  false  EXIT  THEN
  86.         1 ++> addr1  1 ++> addr2
  87.     NEXT
  88.     true  ;
  89.  
  90.  
  91.  
  92. : S=  { addr1 len1 addr2 len2 -- b }
  93.     len1 len2 =
  94.     IF        addr1 addr2 len1 (s=)
  95.     ELSE    false
  96.     THEN
  97. ;
  98.  
  99.  
  100.  
  101. (*    MOVE and ALIGNED_MOVE.
  102.     There's a small problem with MOVE in that it is required by the standard to
  103.     move the data exactly even if the areas overlap, without propagation effects.
  104.     "Undefined on overlap" would have allowed better optimization possiblities,
  105.     although there are probably some situations where the other behavior is
  106.     better.  Anyway we provide both.  We do the "undefined on overlap" with
  107.     ALIGNED_MOVE, which also requires the beginning addresses to be aligned,
  108.     which they usually are anyway.  For MOVE, we call BlockMoveData, which
  109.     does the right thing, and does it well, especially for the longer moves.
  110.     There's about a 28 instruction overhead, but the actual moves are optimum
  111.     for whatever processor we're running on.  So even for ALIGNED_MOVE, we
  112.     call BlockMoveData if the move is long, since for a long enough move there'll 
  113.     always be an advantage in using a processor-specific optimized sequence.
  114.  
  115.     We assume that we're not moving code, only data, so we use BlockMoveData
  116.     rather than BlockMove which flushes the caches.  
  117.     Note we also made this assumption on the 68k, since although we used
  118.     BlockMove (BlockMoveData not being available on all systems) if possible
  119.     we optimized small moves to some inline MOVE instructions without a cache
  120.     flush.
  121.  
  122.     Note also that in a future version the code given here for ALIGNED_MOVE 
  123.     might not always be called if the byte count is a literal.  In this case
  124.     we could sometimes generate a better inline sequence.
  125. *)
  126.  
  127.  
  128. : MOVE    \ ( src dst len -- )
  129.     dup NIF  drop 2drop  EXIT  THEN
  130.     BlockMoveData  ;
  131.  
  132. $ BD36 ' move  2- w!                \ move_h handler code
  133.  
  134. : ALIGNED_MOVE  { src dst len \ cnt -- }
  135.     len 0<=  ?EXIT
  136.     len 32 <=
  137.     IF    len 2 >>  -> cnt
  138.         cnt FOR        src @  dst !
  139.                     4 ++> src  4 ++> dst
  140.             NEXT
  141.         len 3 and  -> cnt
  142.         cnt FOR        src c@  dst c!
  143.                     1 ++> src  1 ++> dst
  144.             NEXT
  145.     ELSE
  146.         src dst len BlockMoveData
  147.     THEN
  148. ;
  149.  
  150. \ $ BD37 ' aligned_move  2- w!        \ alignedMove_h handler code
  151.  
  152.  
  153. : CMOVE  { src dst len -- }
  154.     len FOR
  155.         src c@  dst c!
  156.         1 ++> src  1 ++> dst
  157.     NEXT
  158. ;
  159.  
  160.  
  161. : UPPER  { addr len -- }
  162.     len FOR
  163.         addr c@
  164.         & a  & z  within?
  165.         IF    $ 20 xor  addr c!  ELSE  drop  THEN
  166.         1 ++> addr
  167.     NEXT
  168. ;
  169.  
  170.  
  171. (*    These words are used by the input parsing section.
  172.  
  173.     SCAN ( addr len c -- addr' len' ) searches the string ( addr len )
  174.     for the character c.  addr' is the address of the matching char,
  175.     and len' is the remaining length (including the matching char).  If no
  176.     match, len' will be zero.
  177.  
  178.     Class String+ provides a more complete implementation in its
  179.     chsearch: method, which has case handling.  In the 68k version,
  180.     SCAN only handles a 16-bit length - we don't have this restriction
  181.     in the PPC version, although if you exploit this feature your
  182.     code won't work on the 68k.
  183. *)
  184.  
  185.  
  186. : SCAN { addr len char -- addr' len' }
  187.  
  188.     len FOR
  189.         addr c@ char =
  190.         IF  UNFOR  addr len  EXIT  THEN
  191.         1 ++> addr  1 --> len
  192.     NEXT
  193.     addr 0
  194. ;
  195.  
  196.  
  197. : SKIP  { addr len char -- addr' len' }
  198.  
  199.     len FOR
  200.         addr c@ char <>
  201.         IF  UNFOR  addr len  EXIT  THEN
  202.         1 ++> addr  1 --> len
  203.     NEXT
  204.     addr 0
  205. ;
  206.  
  207. : /STRING  { addr len n -- addr' len' }
  208.     addr n +
  209.     len  n -
  210. ;
  211.  
  212.  
  213. \                ==========================
  214. \                    INPUT PARSING etc.
  215. \                ==========================
  216.  
  217. : SOURCE    \ ( -- addr len )
  218.     src-start src-len  ;
  219.  
  220.  
  221. : REST        \ ( -- addr len )
  222.     src-start    >in @ +
  223.     src-len        >in @ -
  224. ;
  225.  
  226. : SCAN-SRC  { c -- }
  227.     \ Scans the input stream for c.  Leaves the source
  228.     \ updated to the next character, (so it could be empty if the found char
  229.     \ was the last in the buffer) or overshot if none found (>IN exceeding
  230.     \ SRC-LEN).  The caller will need to check for this.
  231.  
  232.     rest c scan
  233.     src-len swap - 1+  >in !
  234.     drop  ;
  235.  
  236.  
  237. : SKIP-SRC  { c -- }
  238.     \ Skips consecutive delimiters equal to c in the source.
  239.     \ Leaves source updated to the next character, or empty if none.
  240.  
  241.     rest c skip
  242.     src-len swap -  >in !
  243.     drop  ;
  244.  
  245.  
  246. : SKIP-SRC+  { c -- }
  247.     \ Skips consecutive delimiters equal to c in the source.
  248.     \ If the source gets exhausted before a non-delimiter is found,
  249.     \ keeps calling REFILL to get more.
  250.  
  251.     BEGIN
  252.         c skip-src
  253.         >in @  src-len <  ?EXIT        \ out on success
  254.         refill                        \ get next input line
  255.     NUNTIL                            \ loop if we got it
  256.     154 die            \ "unexpected end of file"
  257. ;
  258.     
  259.     
  260. : PARSE  { c \ len -- addr len }
  261.     \ Scans the source for delimiter c.  Returns
  262.     \ the addr and len of the parsed string, and updates the source
  263.     \ to the remaining string.
  264.  
  265.     >in @
  266.     c scan-src
  267.     >in @  over -  1-  -> len
  268.     src-start +  len
  269. ;
  270.  
  271.  
  272. : PARSE-WORD  ( c -- addr len )
  273.     \ As for PARSE, but any consecutive initial delimiters are
  274.     \ skipped.  If the input is exhausted in the process,
  275.     \ REFILL is called to get more.
  276.  
  277.     dup skip-src+ parse  ;
  278.  
  279.  
  280. : PARSE-DLM-STR  { c -- addr len }
  281.     \ Scans the source for a string delimited at the
  282.     \ start and end by c.  Everything is skipped before the first delimiter.
  283.     \ If the source gets exhausted in the process, REFILL is called to get
  284.     \ more.
  285.  
  286.     BEGIN
  287.         c scan-src
  288.         >in @  src-len <
  289.         IF    c parse  EXIT  THEN        \ found
  290.         refill
  291.     NUNTIL
  292.     154 die            \ "unexpecte end of file"
  293. ;
  294.         
  295.  
  296. : "STR"  ( -- addr len )  \ Scans for a string delimited by "..."
  297.  
  298.     & "  parse-dlm-str  ;
  299.  
  300.  
  301. : PLACE  { addr1 len addr2 -- }
  302.     \ Converts string ( addr1 len ) to a counted string at addr2.
  303.     \ Appends 3 zero bytes, which may be needed for padding, as
  304.     \ well as making it a valid C string.
  305.  
  306.     addr2 len + 1+  3 erase            \ append zero bytes
  307.     len addr2  c!                    \ store count byte
  308.     addr1  addr2 1+  len  cmove        \ move string bytes over
  309. ;
  310.  
  311.  
  312. : WORD  { c \ addr -- addr }
  313.     \ Parses the source using c as the delimiter (using PARSE-WORD).
  314.     \ Moves the resulting string as a counted string to the CDP with
  315.     \  alignment, and returns this address.
  316.     \ We do the alignment since this may be the start of a new
  317.     \  dictionary header.
  318.  
  319.     c parse-word
  320.     CDP #align4  -> addr
  321.     addr place
  322.     addr
  323. ;
  324.  
  325.  
  326. : WORD" ( -- addr )
  327.     & "  word  ;
  328.  
  329.  
  330. : MWORD  ( -- addr )
  331.     \ "Mops word".  Called by DEFINED? which is called
  332.     \ by INTERPRET.
  333.     \ Calls WORD with a blank as delimiter, and converts the string
  334.     \ to upper case.  Leaves counted string at addr (will be HERE).
  335.  
  336.     bl word
  337.     case_in_names?  ?EXIT
  338.     dup count upper  ;
  339.  
  340.  
  341. : (,STR)  ( addr len --)
  342.     tuck here place
  343.     1+ #align4 allot  ;
  344.  
  345.  
  346. : ,STR  ( c -- )
  347.     \ c is delimiter.  Adds the following text until delimiter
  348.     \ to the DATA AREA as a counted string.
  349.     
  350.     parse  (,str)  ;
  351.  
  352.  
  353. : ,DLM-STR  ( c -- )
  354.     \ Scans the source for a string delimited at the
  355.     \ start and end by c, then adds it to the dictionary.
  356.  
  357.     parse-dlm-str  (,str)  ;
  358.  
  359.  
  360. : ,"  ( -- )        \ Adds text till " to the dictionary.
  361.     & "  ,str  ;
  362.  
  363.  
  364. : ,"STR"  ( -- )    \ Adds text delimited by " at the start and end.
  365.     & "  ,dlm-str  ;
  366.  
  367.  
  368. \ .( - see below, after TYPE
  369.  
  370. : (
  371.     & )  parse  2drop  ;        ppc_immediate
  372.  
  373. : \
  374.     0 -> src-len  ;                ppc_immediate
  375.  
  376.  
  377.  
  378. \                    ======================
  379. \                        SCREEN OUTPUT
  380. \                    ======================
  381.  
  382.  
  383. \ First, the sysCalls and low-level stuff:
  384.  
  385. sysCall  MoveTo
  386. sysCall  EraseRect
  387. sysCall  SetOrigin
  388. sysCall  Line
  389. sysCall  ScrollRect
  390. sysCall  GetPen
  391. sysCall  GetPenState
  392. sysCall  SetPenState
  393. sysCall  PenMode
  394. sysCall  DrawChar
  395. sysCall  DrawText
  396.  
  397.  
  398. : HOME
  399.     8 15  MoveTo  ;
  400.  
  401. : CLS
  402.     fpRect  EraseRect  ;
  403.  
  404. : SCROLL  { x y -- }
  405.     emit?  0EXIT
  406.     fpRect x y theRgn  ScrollRect  ;
  407.  
  408. : >ORIGIN    \ ( x y --)
  409.     SetOrigin  ;
  410.  
  411. : GOTOXY    \ ( x y -- )
  412.     MoveTo  ;
  413.  
  414. : @XY        \ ( -- x y )
  415.     tempVbl GetPen
  416.     tempVbl 2+ w@
  417.     tempVbl    w@
  418. ;
  419.  
  420. : .CURS  ( -- )
  421.     emit?    0EXIT
  422.     curs?    0EXIT
  423.     tempVbl GetPenState
  424.     10  PenMode
  425.     7 0  Line
  426.     tempVbl SetPenState
  427. ;
  428.  
  429.  
  430. : CONTBOT  ( -- n )
  431.     thePort $ A0 + w@  ;
  432.  
  433. : CONTTOP  ( -- n )
  434.     thePort $ 9C +  w@  ;
  435.  
  436. : #LEAD  { \ addr -- n }
  437.     thePort -> addr
  438.  
  439.     thePort $ 4A + w@
  440.     dup NIF        \ zero point size, i.e. no font set.  We just return 4 so Scroll
  441.                 \  doesn't crash.
  442.         drop 4  EXIT
  443.     THEN
  444.     120 *  50 +  100 /
  445. ;
  446.  
  447.  
  448. : #LINES  ( -- n )
  449.     contBot contTop -  #lead /  1-  ;
  450.  
  451.  
  452. : BOTTOM  ( -- n )
  453.     #lead #lines 1- *
  454.     15 +  contTop +  ;
  455.  
  456.  
  457. \            ---------------- CR -----------------
  458.  
  459. : (CR)  ( -- )
  460.     .curs
  461.     @xy  nip 8 swap
  462.     dup bottom >=
  463.     IF    0
  464.         #lead negate  scroll
  465.         gotoXY
  466.     ELSE
  467.         #lead +  gotoXY
  468.     THEN
  469.     .curs
  470. ;
  471.  
  472. ' (cr)    sVect    CRVEC
  473.  
  474. : CR    crVec  ;
  475.  
  476.  
  477. \            ---------------- EMIT -----------------
  478.  
  479. : (EMIT)  { c -- }
  480.     emit?  0EXIT
  481.     c  $ D =
  482.     IF    crVec
  483.     ELSE
  484.         .curs  c DrawChar  .curs
  485.     THEN
  486. ;
  487.  
  488. ' (emit)    sVect    EMITVEC
  489. ' (emit)    sVect    ECHOVEC
  490.  
  491. : EMIT        \ ( c -- )
  492.     1 ++> out  emitVec  ;
  493.  
  494. \ Doug H wants the prompt vectored:
  495.  
  496. : (ok)    & >  emit  ;
  497.  
  498. ' (ok)  vect  OK
  499.  
  500.  
  501. \            ---------------- TYPE -----------------
  502.  
  503. : (TYPE)  { addr len -- }
  504.     emit?  0EXIT
  505.     .curs
  506.     addr 0 len  DrawText
  507.     .curs
  508. ;
  509.  
  510. ' (type)    sVect    TYPEVEC
  511.  
  512. : TYPE  ( addr len -- )
  513.     dup ++> out  typeVec  ;
  514.  
  515.  
  516. : .(
  517.     & )  parse  type  ;            ppc_immediate
  518.  
  519.  
  520. \            -------------- SPACE & SPACES ---------------
  521.  
  522. : SPACE        bl emit  ;
  523.  
  524.  
  525. : (SPACES)  { n -- }
  526.     emit?  0EXIT
  527.     n 0<=  ?EXIT
  528.     
  529.     n padLen min  -> n
  530.     pad n bl fill
  531.     pad n  (type)
  532. ;
  533.  
  534. ' (spaces)    sVect    SPVEC
  535.     
  536. : SPACES    \ ( n -- )
  537.     dup ++> out  spVec  ;
  538.  
  539.  
  540. \ We only use (BS) internally, so we don't define a BS.
  541.  
  542. : (BS)
  543.     .curs                    \ erases any cursor on screen
  544.     curs?  false -> curs?
  545.     @xy swap  6 -  8 max  swap
  546.     2dup gotoXY  space  gotoXY
  547.     -> curs?
  548.     .curs                    \ draw cursor at new position
  549. ;
  550.  
  551.  
  552. : +ECHO        true  -> echo?  ;
  553. : -ECHO        false -> echo?  ;
  554.  
  555. : +CURS        true  -> curs?  ;
  556. : -CURS        false -> curs?  ;
  557. : CURS        curs?  ;            \ for backward compatibility
  558.  
  559.  
  560. \                ===============================
  561. \                        KEYBOARD INPUT
  562. \                ===============================
  563.  
  564.  
  565. : KEY?  ( -- b )
  566.     $ 28  event?  ;
  567.  
  568. : ?TERMINAL  ( -- b )        \ the old name
  569.     key?  ;
  570.  
  571.  
  572. : (KEY)  { \ what -- c }
  573.  
  574.     BEGIN
  575.         fEvent                        \ addr of our event record
  576.         $ 843A                        \ Mask - we'll accept key down, auto-key,
  577.                                     \  mouse-down, high-level and OS events.
  578.         nextEvent
  579.         IF                            \ we've got something
  580.             fEvent w@ -> what        \ get What field of fEvent
  581.             what 3 =  what 5 = or
  582.             IF                        \ we've got a key
  583.                 fEvent 5 + c@        \ low byte of message field is ASCII key value
  584.                 EXIT
  585.             ELSE
  586.                 what 23 =
  587.                 IF                    \ High-level event - presumably oapp.
  588.                                     \ We'll just ignore it.
  589.                 THEN
  590.             THEN
  591.         THEN
  592.     AGAIN
  593. ;
  594.  
  595.  
  596. ' (key)    sVect    KEY
  597.  
  598. forward        get_$input
  599.  
  600. :f get_$input    pad 0  ;f
  601.  
  602.  
  603. : bs_acc
  604.     #tib @                \ at start of TIB?
  605.     IF    (bs)            \ no - fix screen
  606.         -1 #tib +!        \ and back up
  607.     ELSE
  608.         4 beep            \ yes - beep
  609.     THEN
  610. ;
  611.  
  612.  
  613. : key_acc  { \ c loop? -- c }
  614.         \ Reads one key for ACCEPT.  Handles backspaces and tabs.
  615.  
  616.     BEGIN
  617.         false -> loop?
  618.         key -> c
  619.                             \ first we check for the chars which we don't echo
  620.         c 8 =
  621.         IF  bs_acc                    \ handle backspace
  622.         ELSE
  623.             c $ FF =
  624.             IF                        \ ignore FF
  625.  
  626.             ELSE            \ we echo everything else and don't loop
  627.                 c 3 =
  628.                 IF    $ D -> c        \ <enter> replaced with <return>
  629.                 ELSE
  630.                     c 9 =
  631.                     IF    bl -> c        \ tab replaced with blank
  632.                     THEN
  633.                 THEN
  634.                 c echoVec            \ echo char however we're set up to do it
  635.                 c  EXIT
  636.             THEN
  637.         THEN
  638.     AGAIN
  639. ;
  640.  
  641.  
  642. : ACCEPT  { addr max_len \ c -- #chars }
  643.  
  644.     0 #tib !
  645.  
  646. \ Is there pending input from the Mops window?
  647.  
  648.     get_$input  ?dup
  649.     IF                    \ yes - move it to the destination.  We can
  650.                         \  assume special chars have been filtered.
  651.         max_len min
  652.         dup #tib !
  653.         addr swap cmove  EXIT
  654.     THEN
  655.     drop
  656.  
  657.     BEGIN
  658.         key_acc  -> c
  659.         c $ D =
  660.         IF  #tib @  EXIT  THEN
  661.         
  662.         #tib @ max_len <
  663.         IF  c  addr #tib @ + c!        \ still room in buff - store char
  664.             1 #tib +!
  665.         THEN
  666.     AGAIN
  667. ;
  668.  
  669.  
  670. : SET_SOURCE
  671.     TIB        -> src-start
  672.     #tib @    -> src-len
  673.     0 >in !
  674. ;
  675.  
  676. : QUERY
  677.     TIB TIBlen  accept drop
  678.     set_source
  679.     0 -> source-ID
  680. ;
  681.  
  682. :f REFILL ( -- b )    \ attempts to (re)fill the input stream with another line.
  683.     source-ID dup
  684.     NIF                    \ it's from the keyboard
  685.         drop  query
  686.         true
  687.     ELSE
  688.         -1 =
  689.         IF                \ it's from an EVALUATEd string - none left
  690.             false
  691.         ELSE            \ it's from a file
  692.             fRefill        \ - fRefill does the job, and returns the flag.
  693.         THEN
  694.     THEN
  695.     1 ++> #lines_read
  696. ;f
  697.  
  698.  
  699. \                    =====================
  700. \                        NUMBER INPUT
  701. \                    =====================
  702.  
  703.  
  704. : >NUMBER  ( ud-lo ud-hi ) { addr len -- ud-lo' ud-hi' addr' len' }
  705.     len 0>
  706.     IF
  707.         BEGIN
  708.             addr c@  1 ++> addr
  709.             base digit
  710.             NIF    1 --> addr  false
  711.             ELSE
  712.              ( ud-lo ud-hi digit )
  713.                  swap base * rot base um*  d+
  714.                 dpl 0>= IF  1 ++> dpl  THEN
  715.                 1 --> len
  716.                 len 0>
  717.             THEN
  718.         NUNTIL
  719.     THEN
  720.     ( ud-lo' ud-hi' )  addr len
  721. ;
  722.  
  723.  
  724. : ?NOTFOUND  ( flag -- )
  725.     NIF     -13 die  THEN        \ "undefined word"
  726. ;
  727.  
  728.  
  729. : NUM?  { addr len \ start neg? done? -- n true | -- n-lo n-hi true | -- false }
  730.  
  731.     false -> neg?  false -> done?
  732.  
  733.     len NIF  false  EXIT  THEN
  734.  
  735.     addr c@ & - =
  736.     IF            \ 1st char was minus
  737.         true -> neg?
  738.         1 ++> addr  1 --> len
  739.     THEN
  740.     addr -> start                \ remember initial addr
  741.     -1 -> dpl                    \ no decimal point seen yet
  742.     0 0                            \ initial number is a double zero
  743.     BEGIN
  744.         addr len  >number        \ accumulate digits into number
  745.         -> len -> addr            \ update string addr & len
  746.         len
  747.         IF    addr c@  & . =
  748.             IF  addr -> dpl
  749.                 1 ++> addr  1 --> len
  750.             ELSE
  751.                 true -> done?
  752.             THEN
  753.         ELSE
  754.             true -> done?
  755.         THEN
  756.     done?
  757.     UNTIL
  758.  
  759. \ we've hit a non-digit or the string is exhausted.
  760.  
  761.     len IF            2drop false  EXIT  THEN        \ 'number' not completed - probably
  762.                                                 \  bad char in number
  763.     addr start = IF    2drop false  EXIT  THEN        \ no chars processed - not a number
  764.  
  765.     dpl 0>=
  766.     IF                \ decimal point seen - it's a double number
  767.         neg? IF  dnegate  THEN
  768.     ELSE
  769.         drop        \ want a single number - drop hi cell
  770.         neg? IF  negate  THEN
  771.     THEN
  772.     true
  773. ;
  774.  
  775. : NUMBER  ( addr -- n )        \ returns the number at addr, or if none,
  776.                             \ gives "undefined word" error.
  777.     count  num? ?notFound  ;
  778.  
  779.  
  780. \ LITERAL is immediate so we'll leave it till the end.
  781.  
  782. \    head    $47,LITERAL,literal        ; LITERAL
  783. \    callh    hLiteral
  784. \    RTS
  785.  
  786.  
  787. \            =============================
  788. \                       NUMBER OUTPUT
  789. \            =============================
  790.  
  791. : HOLD  ( c -- )
  792.     1 --> hld  hld c!  ;
  793.  
  794.  
  795. : <#  ( d -- d )
  796.     pad -> hld  ;
  797.  
  798. : #>  ( d -- )
  799.     2drop
  800.     hld pad over -  ;
  801.  
  802.  
  803. : SIGN  ( n -- )
  804.     0< IF  & -  hold  THEN  ;
  805.  
  806. (*
  807. : #
  808.     drop        \ get rid of hi-order cell (assumed to be zero)
  809.     base  u/mod
  810.     swap
  811.     dup 9 > IF  7 +  THEN
  812.     & 0  +  hold
  813.     0
  814. ;
  815. *)
  816.  
  817. : #
  818.     base 0  ud/mod  2swap drop
  819.     dup 9 > IF  7 +  THEN
  820.     & 0  +  hold
  821. ;
  822.  
  823.  
  824. : #S  ( d -- d' )
  825.     BEGIN  #  2dup or  NUNTIL  ;
  826.  
  827. \ : HEX        16 -> base  ;
  828. \ : DECIMAL    10 -> base  ;
  829.  
  830.  
  831. : .R  { n #to-right -- }
  832.     n abs  0
  833.     <#  #s  n sign  #>
  834.     #to-right over -  spaces
  835.     type
  836. ;
  837.  
  838. : .        \ ( n -- )
  839.     0 .r space  ;
  840.  
  841. : .H
  842.     base  16 -> base
  843.     swap .
  844.     -> base  ;
  845.  
  846. : U.
  847.     0 <# #s #>  type  space  ;
  848.  
  849.  
  850. : N>COUNT
  851.     count  $ 1F and  ;
  852.  
  853.